
#include <string.h>
#include <stdint.h>
#include "Flash.h"
#include "BooterConfig.h"
#include "Bsp.h"


static uint32_t FlashPageSize;
static uint32_t FlashSize;
static uint32_t FlashMaxAddress;
static uint32_t BootMaxAddress = APP_ADDRESS - 2048;
static uint32_t BootFlagBaseAddress;

static FlashArea_T AppArea;
static uint8_t FlashPageBuffer[2048];
static uint32_t CachAddress;
static uint32_t CachOffset;
static uint32_t appCompeletFlag;


static inline uint32_t Flash_GetSize(void)
{
	return 256 * 1024;
}


void Flash_Init(void)
{
	FlashSize = Flash_GetSize();
	FlashPageSize = FMC_PAGE_SIZE;

	FlashMaxAddress = FLASH_START_ADDRESS + FlashSize;
	BootMaxAddress = APP_ADDRESS - FlashPageSize;
	BootFlagBaseAddress = APP_ADDRESS - FlashPageSize;
	AppArea.Address = APP_ADDRESS;
	AppArea.Size = FlashSize - (APP_ADDRESS - FLASH_START_ADDRESS);
}


uint32_t Flash_MaxAddress(void)
{
	return FlashMaxAddress;
}


FlashArea_T * Flash_GetAppArea(void)
{
	return & AppArea;
}


uint32_t Flash_ErasePages(uint32_t Start_Address, uint32_t Total)
{
	uint32_t ErrorCode = 0;
	uint32_t Index;
	uint32_t PageAddress = Start_Address;
	fmc_state_enum fmc_state = FMC_READY;

	fmc_unlock();

	for (Index = 0; Index < Total; Index++) {
		fmc_flag_clear(FMC_FLAG_BANK0_END);
		fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
		fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
		fmc_state = fmc_page_erase(PageAddress);
		if(fmc_state){
			ErrorCode = 1;
			break;
		}
		PageAddress += FlashPageSize;
	}

	fmc_lock();
	return ErrorCode;
}


uint32_t Flash_EraseAppArea(void)
{
	uint32_t ErrorCode = 0;
	FlashArea_T * App = Flash_GetAppArea();

	ErrorCode = Flash_ErasePages(App->Address, App->Size / FlashPageSize);
	return ErrorCode;
}


void Flash_Read32Buf(uint32_t address, uint32_t buf[], uint32_t len)
{
	uint32_t i;
	volatile uint32_t * ptrd = (volatile uint32_t *)address;

	for (i = 0; i < len; i++) {
		buf[i] = ptrd[i];
	}
}


uint32_t Flash_Write32Buf(uint32_t address, uint32_t buf[], uint32_t len)
{
	uint32_t i;
	fmc_state_enum fmc_state = FMC_READY;
	uint32_t r;
	
	fmc_unlock();

	for (i = 0; i < len; i++) {
		fmc_flag_clear(FMC_FLAG_BANK0_END);
		fmc_flag_clear(FMC_FLAG_BANK0_WPERR);
		fmc_flag_clear(FMC_FLAG_BANK0_PGERR);
		fmc_state = fmc_word_program(address, buf[i]);

		if (fmc_state != FMC_READY) {
			break;
		}
		r = * (volatile uint32_t *)address;
		if (buf[i] != r) {
			fmc_state = FMC_PGERR;
			break;
		}

		address += sizeof(buf[0]);
	}

	fmc_lock();

	return fmc_state;
}


void Flash_Cach(uint32_t pageAddress)
{
	Flash_Read32Buf(pageAddress, (uint32_t *) FlashPageBuffer, FlashPageSize / sizeof(uint32_t));
	CachAddress = pageAddress;
}


int Flash_Sync(void)
{
	int ErrorCode = 0;

	if ((CachOffset != 0) && (CachAddress != 0)) {
		uint32_t ret;

		ret = Flash_Write32Buf(CachAddress, (uint32_t *) FlashPageBuffer, FlashPageSize / sizeof(uint32_t));

		if (ret) {
			ErrorCode = -1;
		}
	}

	return ErrorCode;
}


static int Flash_WriteInPage(uint32_t page, uint32_t offset, uint8_t buffer[], uint32_t length)
{
	uint32_t maxLength = FlashPageSize - offset;
	uint32_t writeLength = length < maxLength ? length: maxLength;

	if (page != CachAddress) {
		int ret;

		ret = Flash_Sync();

		if (ret) {
			return ret;
		}

		Flash_Cach(page);
	}

	memcpy(FlashPageBuffer + offset, buffer, writeLength);
	CachOffset = offset + writeLength;
	return writeLength;
}


static uint32_t Flash_DoWriteData(uint32_t Address, uint8_t Data[], uint32_t Len)
{
	uint32_t page, offset;
	int written;
	uint8_t * pdata = Data;
	uint32_t remain = Len;
	uint32_t addr = Address;

	while (remain > 0) {
		offset = addr & (FlashPageSize - 1);
		page = addr - offset;
		written = Flash_WriteInPage(page, offset, pdata, remain);

		if (written < 0) {
			return ERR_WRITE_FAIL;
		}

		pdata += written;
		remain -= written;
		addr += written;
	}

	return 0;
}


uint32_t Flash_WirteData(uint32_t Address, uint8_t Data[], uint32_t Len)
{

	if (Len == 0) {
		return 0;
	}

	if (Address < BootMaxAddress) {
		return ERR_ADDR_OVERFLOW;
	}

	if (Address + Len > FlashMaxAddress) {
		return 9;
	}

	return Flash_DoWriteData(Address, Data, Len);
}



uint32_t flagSave[FlagMaxNum];


void Flash_FlagInit(void)
{
	Flash_Read32Buf(BootFlagBaseAddress, flagSave, FlagMaxNum);
}


uint32_t Flash_ReadFlag(uint32_t number)
{
	if (number < FlagMaxNum) {
		return flagSave[number];
	}

	return 0xFFFFFFFF;
}


uint32_t Flash_ModifyFlag(uint32_t number, uint32_t flag)
{
	if (number < FlagMaxNum) {
		flagSave[number] = flag;
		return 0;
	}

	return 1;
}


uint32_t Flash_UpdateFlag(void)
{
	uint32_t ret = 1;

	fmc_unlock();
	ret = fmc_page_erase(BootFlagBaseAddress);
	fmc_lock();

	if (!ret) {
		ret = Flash_Write32Buf(BootFlagBaseAddress, flagSave, FlagMaxNum);
	}

	return ret;
}



uint32_t Flash_ReadAppCompeletFlag(void)
{
	uint32_t flag;
	Flash_Read32Buf(APP_ADDRESS, &flag, 1);
	return flag;
}


uint32_t Flash_SyncAppCompeletFlag(void){
	return Flash_Write32Buf(APP_ADDRESS, &appCompeletFlag, 1);
}

void Flash_WriteAppCompeletFlag(uint32_t flag)
{
	appCompeletFlag = flag;

}


















































